/*//////////////////////////////////////////////////////////////////////////////
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2002-2007 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_defs.h"
#if defined (UMC_ENABLE_MP3_INT_AUDIO_ENCODER)

#include "mp3enc_own_int.h"

MP3Status mp3iencUpdateMemMap(MP3Enc *state, Ipp32s shift)
{
  Ipp32s i;

  for (i = 0; i < 32; i++) {
    MP3_UPDATE_PTR(void, state->com.htables[i].phuftable, shift)
  }
  MP3_UPDATE_PTR(IppsFFTSpec_R_16s, state->ipa_pFFTSpecShort, shift)
  MP3_UPDATE_PTR(IppsFFTSpec_R_16s, state->ipa_pFFTSpecLong, shift)
  MP3_UPDATE_PTR(Ipp8u, state->ipa_pBuffer, shift)

  for (i = 0; i < 3; i++) {
    MP3_UPDATE_PTR(samplefbout, state->fbout_int[i], shift);
  }
  return MP3_OK;
}

static Ipp32s mp3iencCalcSlotSize(MP3Enc *state) {
  IppMP3FrameHeader *header = &state->com.header;
  Ipp32s i, size;

  for (i = 1; i < 15; i++) {
    size = 0;

    if (header->layer == 3) {
      size = 72000 * (header->id + 1);
    } else if (header->layer == 2) {
      size = 72000 * 2;
    } else if (header->layer == 1) {
      size = 12000;
    }

    size = size * mp3_bitrate[header->id][header->layer - 1][i] /
      mp3_frequency[header->id][header->samplingFreq];

    header->paddingBit = 0;

    if (header->layer == 1)
      size *= 4;

    state->com.slot_sizes[i] = size;
  }

  state->com.slot_size = state->com.slot_sizes[header->bitRate];

  return 0;
}

MP3Status mp3iencInit(MP3Enc *state,
                      Ipp32s sampling_frequency,
                      Ipp32s stereo,
                      Ipp32s layer,
                      Ipp32s bitrate,
                      Ipp32s br_mode,
                      Ipp32s stereo_mode,
                      Ipp32s ns_mode,
                      Ipp32s *size_all)
{
    Ipp32s freq, id, br;
    Ipp32s j, cutoff_frequency;
    Ipp16s short_cutoff_frequency;
    Ipp32s samp_rate_per_ch, inScaleFactor;
    Ipp16s short_tmp;
    Ipp32u *sfb_long, *sfb_short;
    Ipp32s sfb_l_max = 0, sfb_s_max = 0;
    Ipp32s size, ts;
    Ipp8u *mem;

    size = 0;
    mem = NULL;

    switch (sampling_frequency) {
    case 44100:
      freq = 0;
      id = 1;
      break;
    case 48000:
      freq = 1;
      id = 1;
      break;
    case 32000:
      freq = 2;
      id = 1;
      break;
    case 22050:
      freq = 0;
      id = 0;
      break;
    case 24000:
      freq = 1;
      id = 0;
      break;
    case 16000:
      freq = 2;
      id = 0;
      break;
    default:
      return MP3_FAILED_TO_INITIALIZE;
    }

    if (layer < 3 || layer > 3 || id == 0) {
      return MP3_FAILED_TO_INITIALIZE;
    }

    if (ns_mode < 0 || ns_mode > 1) {
      return MP3_FAILED_TO_INITIALIZE;
    }

    if (br_mode != MPAENC_CBR && br_mode != MPAENC_ABR) {
      return MP3_FAILED_TO_INITIALIZE;
    }

    if ((stereo != 1 && stereo != 2) ||
        !mp3enc_checkBitRate(id, layer, stereo, bitrate, &br)) {
        return MP3_FAILED_TO_INITIALIZE;
    }

    ts = sizeof(MP3Enc);
    size += ts;
    if (state)
      mem = (Ipp8u *)state + ts;

    if (state) {
      ippsZero_8u((Ipp8u *)state, sizeof(MP3Enc));

      state->com.header.samplingFreq = freq;
      state->com.header.bitRate = br;

      state->com.header.id = id;
      state->com.grnum = 2;
      state->com.header.layer = layer;   // layer 3
      state->com.header.protectionBit = 1; // enable CRC

      if (br == 1)
        br_mode = MPAENC_CBR; // use CBR for minimal bitrate

      state->com.br_mode = br_mode;
      state->com.stereo = stereo;
      state->com.frameSize = 1152;

      state->com.si_main_data_begin = 0;
      state->com.main_data_ptr = 0;
      state->com.resr_bytes = 0;
      state->com.resr_mod_slot = 0;

      state->com.quant_mode_fast = 0;

      state->com.framesNum = 0;

      state->com.ns_mode = ns_mode;
      state->com.stereo_mode =
        state->com.stereo_mode_param = stereo_mode;

      samp_rate_per_ch = (mp3_bitrate[state->com.header.id]
        [state->com.header.layer-1][state->com.header.bitRate] * 1000) >> (stereo - 1);

      inScaleFactor = 0;
      while (samp_rate_per_ch >= 32768) {
        inScaleFactor += 1;
        samp_rate_per_ch >>= 1;
      }

      short_tmp = (Ipp16s)samp_rate_per_ch;
      ippsPow34_16s_Sfs(&short_tmp, inScaleFactor, &short_cutoff_frequency, 0, 1);
      cutoff_frequency = short_cutoff_frequency * 8;

      state->com.lowpass_maxline = 32 * cutoff_frequency / mp3_frequency[state->com.header.id][state->com.header.samplingFreq];
      if (state->com.lowpass_maxline > 32)
          state->com.lowpass_maxline = 32;

      sfb_long = mp3enc_sfBandIndex[state->com.header.id][state->com.header.samplingFreq].l;
      sfb_short = mp3enc_sfBandIndex[state->com.header.id][state->com.header.samplingFreq].s;

      for (j = 0; j < SBBND_L; j++)
        if ((Ipp32s)sfb_long[j] < state->com.lowpass_maxline * 18)
          sfb_l_max = j + 1;

      for (j = 0; j < SBBND_S; j++)
        if ((Ipp32s)sfb_short[j] * 3 < state->com.lowpass_maxline * 18)
          sfb_s_max = j + 1;

      state->com.sfb_l_max = sfb_l_max;
      state->com.sfb_s_max = sfb_s_max;

      state->common_scalefactor_update[0] = 2;
      state->common_scalefactor_update[1] = 2;
      state->last_frame_common_scalefactor[0] = 210;
      state->last_frame_common_scalefactor[1] = 210;

      ippsZero_16s(&state->input_buffer_short[0][0], 2 *(1152 + 224 + 576));

      state->com.si_private_bits = 0;

      state->com.si_beg = 0;
      state->com.si_new = 0;
      state->com.si_num = 0;

      state->fbout_prev = 0;

      for (j = 0; j < 3; j++) {
        Ipp32s ind;
        ind = state->fbout_prev + j;
        if (ind > 2) ind -= 3;
        state->fbout_int[j] = &state->fbout_data[ind];
      }
      mp3iencCalcSlotSize(state);
    }

    mp3ienc_mdctInit(state);

    mp3enc_huffInit(mem ? state->com.htables : NULL, mem, &ts);
    size += ts;
    if (mem) mem += ts;

    mp3ienc_psychoacousticInit(state, mem, &ts);
    size += ts;
    if (mem) mem += ts;

    if(size_all)
      *size_all = size;

    return MP3_OK;
}

MP3Status mp3iencClose(MP3Enc *state)
{
    state->com.si_private_bits = 0;

    return MP3_OK;
}

MP3Status mp3iencGetFrame(Ipp16s *inPointer, Ipp32s *encodedBytes,
                          Ipp8u *outPointer, MP3Enc *state)
{
    VM_ALIGN16_DECL(Ipp16s) buffer[2][1152];
    Ipp16s *buff[2];
    Ipp32s ch, gr;
    Ipp32s stereo;
    Ipp16s *input_data[4];

    if (!state || !encodedBytes || !inPointer || !outPointer)
      return MP3_NULL_PTR;

    buff[0] = buffer[0];
    buff[1] = buffer[1];
    input_data[0] = state->input_buffer_short[0];
    input_data[1] = state->input_buffer_short[1];
    input_data[2] = state->input_buffer_short[2];
    input_data[3] = state->input_buffer_short[3];

    stereo = state->com.stereo;

    ippsDeinterleave_16s(inPointer, stereo, state->com.frameSize, buff);

    for (ch = 0; ch < stereo; ch++) {
        ippsCopy_16s(&(state->input_buffer_short[ch][1152]), &(state->input_buffer_short[ch][0]), 576);
        ippsCopy_16s(buff[ch], &state->input_buffer_short[ch][576], 1152);
    }
    if (state->com.stereo_mode_param == MPA_MS_STEREO ||
      state->com.stereo_mode_param == MPA_JOINT_STEREO) {
        const Ipp32s mult_i = 23170; /* sqrt(2)/2 q15 */
        Ipp32s li, ri;
        Ipp32s k;
        for (ch = 2; ch < 4; ch++) {
          ippsCopy_16s(&(state->input_buffer_short[ch][1152]), &(state->input_buffer_short[ch][0]), 576);
        }
        for (k = 0; k < 1152; k++) {
          li = mult_i * (buff[0][k] + (Ipp32s)buff[1][k]);
          ri = mult_i * (buff[0][k] - (Ipp32s)buff[1][k]);
          state->input_buffer_short[2][576 + k] = (Ipp16s)(li >> 16);
          state->input_buffer_short[3][576 + k] = (Ipp16s)(ri >> 16);
        }
    }
    mp3ienc_psychoacoustic(state, input_data);

// filterbank
    for (gr = 0; gr < 2; gr++) {
        for (ch = 0; ch < stereo; ch++) {
            Ipp32s subband;
            for ( subband = 0; subband < 18; subband++ ) {
                ippsAnalysisPQMF_MP3_16s32s(
                    &(state->input_buffer_short[ch][1 + gr * 576 + subband * 32]),
                    (Ipp32s *)&((*(state->fbout_int[gr+1]))[ch][subband][0]), 1);
            }
        }
    }

    mp3ienc_mdctBlock(state);

    mp3ienc_quantization(state);

    *encodedBytes = mp3enc_formatBitstream_l3(&state->com, state->mdct_out_int, outPointer);

    state->com.framesNum++;

    return MP3_OK;
}

MP3Status mp3iencGetSlotSize(MP3Enc *state, Ipp32s *slot_size)
{
  *slot_size = state->com.slot_size;
  return MP3_OK;
}

#endif //UMC_ENABLE_MP3_INT_AUDIO_ENCODER
